package cn.htsyb.synergy.orm.jpa.service;

import cn.htsyb.synergy.orm.constant.DeleteMode;
import cn.htsyb.synergy.orm.constant.ValidStatus;
import cn.htsyb.synergy.orm.jpa.criterion.DynamicBuilder;
import cn.htsyb.synergy.orm.jpa.criterion.OrderExpress;
import cn.htsyb.synergy.orm.jpa.criterion.QueryExpress;
import cn.htsyb.synergy.orm.jpa.model.entity.AbsIdStatusEntity;
import cn.htsyb.synergy.orm.jpa.model.param.PageParam;
import cn.htsyb.synergy.orm.jpa.repository.IJpaCommonRepository;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.annotation.Resource;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.lang.Nullable;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.util.Collection;
import java.util.List;
import java.util.Optional;

/**
 * @author lakeside hubin_yuan.410@hotmail.com
 * @version V1.0.0
 * @date 2022/5/11
 * @since 1.0
 */
@Transactional
public interface IJpaCommonService<T extends AbsIdStatusEntity, ID> extends ICommonService {
    ObjectMapper objectMapper = new ObjectMapper();

    /**
     * 基于json更新对象字段
     *
     * @param entry
     * @param jsonNode
     * @return
     * @throws Exception
     */
    default T readerForUpdatingOnField(@Nullable T entry, @Nullable JsonNode jsonNode) throws Exception {
        Assert.isTrue(!jsonNode.isArray(), "不能使用数组设置更新字段");
        Assert.isTrue(!jsonNode.has("id"), "更新字段中不能存在主键编号字段");
        return objectMapper.readerForUpdating(entry).readValue(jsonNode);
    }

    /**
     * 基于json更新对象
     *
     * @param jsonNode
     * @return
     * @throws Exception
     */
    default T readerForUpdatingOnEntity(@Nullable JsonNode jsonNode) throws Exception {
        Assert.isTrue(!jsonNode.isArray(), "不能使用数组设置更新字段");
        Assert.isTrue(jsonNode.has("id"), "json中必须包含主键编号字段");
        T entry = findById((ID) jsonNode.get("id").asText());
        Assert.notNull(entry, "实体对象不存在");
        return objectMapper.readerForUpdating(entry).readValue(jsonNode);
    }

    @Resource
    IJpaCommonRepository<T, ID> getRepository();

    /**
     * 检测对象是否存在
     *
     * @param id 主键编号
     */
    default Boolean exitsById(@Nullable ID id) {
        return getRepository().existsById(id);
    }

    /**
     * 查找对象
     *
     * @param id 主键编号
     */
    default T findById(@Nullable ID id) {
        Optional<T> optional = getRepository().findById(id);
        return optional.orElse(null);
    }

    /**
     * 查找多个对象
     *
     * @param tCollection 多个主键编号
     */
    default List<T> findAllByIds(@Nullable Collection<ID> tCollection) {
        return getRepository().findAllById(tCollection);
    }

    /**
     * 删除对象
     *
     * @param tCollection 多个主键编号
     * @param deleteMode  输出模式
     */
    default void deleteByIds(@Nullable Collection<ID> tCollection, DeleteMode deleteMode) {
        if (deleteMode.equals(DeleteMode.logical)) {
            getRepository().updateValidStatus(ValidStatus.deleted, tCollection);
        } else if (deleteMode.equals(DeleteMode.physics)) {
            getRepository().deleteByIdIn(tCollection);
        }
    }

    /**
     * 保存实体
     *
     * @param t 实体对象
     */
    default T saveEntity(@Nullable T t) {
        return getRepository().save(t);
    }

    /**
     * 保存多个实体
     *
     * @param tCollection 多个实体对象
     */
    default List<T> saveAllEntity(@Nullable Collection<T> tCollection) {
        return getRepository().saveAll(tCollection);
    }

    /**
     * 按条件统计实体个数
     *
     * @param searchByArr
     * @param filterByArr
     * @return
     */
    default Long countAll(Collection<QueryExpress> searchByArr, Collection<QueryExpress> filterByArr) {
        Specification<T> specification = DynamicBuilder.specification(searchByArr, filterByArr);
        return getRepository().count(specification);
    }

    /**
     * 按条件查找多个对象
     *
     * @param searchByArr
     * @param orderByArr
     * @return
     */
    default List<T> findAllList(Collection<QueryExpress> searchByArr, Collection<QueryExpress> filterByArr, Collection<OrderExpress> orderByArr) {
        Specification<T> specification = DynamicBuilder.specification(searchByArr, filterByArr);
        Sort sort = DynamicBuilder.getSort(orderByArr);
        return getRepository().findAll(specification, sort);
    }


    /**
     * 按条件分页查找多个对象
     *
     * @param searchByArr
     * @param filterByArr
     * @param orderByArr
     * @param pageParam
     * @return
     */
    default Page<T> findAllPage(Collection<QueryExpress> searchByArr, Collection<QueryExpress> filterByArr, Collection<OrderExpress> orderByArr, PageParam pageParam) {
        PageRequest pageable = DynamicBuilder.getPageRequest(pageParam.getPage(), pageParam.getSize(), orderByArr);
        Specification<T> specification = DynamicBuilder.specification(searchByArr, filterByArr);
        return getRepository().findAll(specification, pageable);
    }

}
